#include "FormChatRoom.h"

FormChatRoom::FormChatRoom(QWidget * parent)
            : BaseFormWidget(parent)
            , m_bExit(false)
            , m_pNodeClient(nullptr)
            , m_pServerIP(nullptr)
            , m_pServerPort(nullptr)
            , m_pServerKey(nullptr)
            , m_pFriendInfo(nullptr)
            , m_pMsgShowInfo(nullptr)
            , m_pMsgInput(nullptr)
{
    // 注册节点更新结构体到信号中使用
    qRegisterMetaType<QList<NODE_INFO>>("QList<NODE_INFO>");

    // 清空节点ID记录
    m_strNodeId.clear();

    // 创建主要控件
    newMainFunc();

    // 创建功能按钮
    newFuncPtb();

    // 添加顶部工具栏
    newBaseClose();

    // 所有按钮统一设置风格
    setBaseFont(gstFont);

    // 连接本对象信号，用于消息线程异步消息展示
    connect(this, SIGNAL(sengMsg2Show(QString, QString)), this, SLOT(slt_ShowMsgInfo(QString, QString)));

    // 创建客户端
    m_pNodeClient = new nodeClient;

    try
    {
        m_thMsgProc = std::thread(&FormChatRoom::threadMsgProc, this);
    }
    catch(...)
    {
        return;
    }
    
#if 1
    m_pClientID->setText(QString("cai"));
    m_pServerIP->setText(QString("192.168.2.102"));
    m_pServerPort->setText(QString("2656"));
    m_pServerKey->setText(QString("test123"));
#endif
}

FormChatRoom::~FormChatRoom()
{
    release();
}

// 资源释放
void FormChatRoom::release()
{
    m_bExit = true;

    if(nullptr != m_pNodeClient)
    {
        m_pNodeClient->setCallBackExit();
    }

    if(m_thMsgProc.joinable())
    {
        m_thMsgProc.join();
    }

    if(nullptr != m_pNodeClient)
    {
        delete m_pNodeClient;
        m_pNodeClient = nullptr;
    }
}

// 创建主要控件
void FormChatRoom::newMainFunc()
{
    QHBoxLayout* pMainFunc = new QHBoxLayout;
    addLayout2BaseLayout(pMainFunc);
    pMainFunc->setSpacing(6);

    // 添加群主信息输入和群友列表
    QVBoxLayout *pBaseInfo = new QVBoxLayout;
    pMainFunc->addLayout(pBaseInfo);
    QGroupBox *pBoxServerInfo = new QGroupBox(this);
    QGroupBox *pBoxFriendInfo = new QGroupBox(this);
    pBoxServerInfo->setTitle(QStringLiteral("鱼塘信息"));
    pBoxFriendInfo->setTitle(QStringLiteral("鱼情"));
    pBoxServerInfo->setFont(gstFont);
    pBoxFriendInfo->setFont(gstFont);
    pBaseInfo->addWidget(pBoxServerInfo);
    pBaseInfo->addWidget(pBoxFriendInfo);

    QFormLayout *pServerInfo = new QFormLayout;
    pBoxServerInfo->setLayout(pServerInfo);
    
    m_pClientID = new QLineEdit(pBoxServerInfo);
    m_pServerIP = new QLineEdit(pBoxServerInfo);
    m_pServerPort = new QLineEdit(pBoxServerInfo);
    m_pServerKey = new QLineEdit(pBoxServerInfo);
    m_pClientID->setAlignment(Qt::AlignCenter);
    m_pServerIP->setAlignment(Qt::AlignCenter);
    m_pServerPort->setAlignment(Qt::AlignCenter);
    m_pServerKey->setAlignment(Qt::AlignCenter);
    m_pClientID->setPlaceholderText(QStringLiteral("我的ID"));
    m_pServerIP->setPlaceholderText(QStringLiteral("有效IP地址"));
    m_pServerPort->setPlaceholderText(QStringLiteral("端口号"));
    m_pServerKey->setPlaceholderText(QStringLiteral("准确口令"));

    QLabel* pLabelID = new QLabel(pBoxServerInfo);
    QLabel* pLabelIP = new QLabel(pBoxServerInfo);
    QLabel* pLabelPort = new QLabel(pBoxServerInfo);
    QLabel* pLabelKey = new QLabel(pBoxServerInfo);
    pLabelID->setText(QString("ID"));
    pLabelIP->setText(QString("IP"));
    pLabelPort->setText(QString("端口"));
    pLabelKey->setText(QString("口令"));
    pLabelID->setAlignment(Qt::AlignCenter);
    pLabelIP->setAlignment(Qt::AlignCenter);
    pLabelPort->setAlignment(Qt::AlignCenter);
    pLabelKey->setAlignment(Qt::AlignCenter);

    pServerInfo->addRow(pLabelID, m_pClientID);
    pServerInfo->addRow(pLabelIP, m_pServerIP);
    pServerInfo->addRow(pLabelPort, m_pServerPort);
    pServerInfo->addRow(pLabelKey, m_pServerKey);


    QVBoxLayout *pFriendInfo = new QVBoxLayout;
    pBoxFriendInfo->setLayout(pFriendInfo);
    m_pFriendInfo = new QTextBrowser(pBoxFriendInfo);
    pFriendInfo->addWidget(m_pFriendInfo);

    // 添加消息通知和输入栏
    QGroupBox *pBoxMsgInfo = new QGroupBox(this);
    pBoxMsgInfo->setTitle(QString("鱼塘消息"));
    pBoxMsgInfo->setFont(gstFont);
    pMainFunc->addWidget(pBoxMsgInfo, Qt::AlignRight);

    QVBoxLayout *pMsgInfo = new QVBoxLayout;
    pBoxMsgInfo->setLayout(pMsgInfo);

    m_pMsgShowInfo = new QTextBrowser(pBoxMsgInfo);
    m_pMsgInput = new QTextEdit(pBoxMsgInfo);
    QHBoxLayout* pFunc = new QHBoxLayout;
    pMsgInfo->addWidget(m_pMsgShowInfo);
    pMsgInfo->addWidget(m_pMsgInput);
    pMsgInfo->addLayout(pFunc);

    QPushButton *pBtnClear = NewPTBWithIcon(QString("清空"), QString("清空数据"), QIcon(QString(":/operationIcons/resource/operationIcons/delete.ico")), this);
    QPushButton *pBtnSend = NewPTBWithIcon(QString("发送"), QString("发送数据"), QIcon(QString(":/operationIcons/resource/operationIcons/send.ico")), this);
    connect(pBtnClear, SIGNAL(clicked()), this, SLOT(slt_Clear()));
    connect(pBtnSend, SIGNAL(clicked()), this, SLOT(slt_Send()));

    pFunc->addStretch();
    pFunc->addWidget(pBtnClear);
    pFunc->addWidget(pBtnSend);

    m_pMsgInput->setMaximumHeight(100);
}

// 创建功能按钮
void FormChatRoom::newFuncPtb()
{
    m_pBtnConnect = NewPTBWithIcon(QString("连接"), QString("连接到服务端"), QIcon(QString(":/operationIcons/resource/operationIcons/connect.ico")), this);
    m_pBtnDisConnect = NewPTBWithIcon(QString("断开"), QString("从服务端连接中断开"), QIcon(QString(":/operationIcons/resource/operationIcons/disconnected.ico")), this);
    QPushButton *pBtnRefresh = NewPTBWithIcon(QString("刷新"), QString("刷新群组"), QIcon(QString(":/operationIcons/resource/operationIcons/refresh.ico")), this);
    connect(m_pBtnConnect, SIGNAL(clicked()), this, SLOT(slt_Connect()));
    connect(m_pBtnDisConnect, SIGNAL(clicked()), this, SLOT(slt_Disconnect()));
    connect(pBtnRefresh, SIGNAL(clicked()), this, SLOT(slt_Update()));

    addBaseToolFunc(m_pBtnConnect);
    addBaseToolFunc(m_pBtnDisConnect);
    addBaseToolFunc(pBtnRefresh);

    // 后续按钮靠右排列
    addBaseFuncStretch();

    // 配置按钮初始化状态
    m_pBtnDisConnect->setEnabled(false);
}

// 连接到服务端
void FormChatRoom::slt_Connect()
{
    if(nullptr == m_pNodeClient)
    {
        qDebug() << "FormChatRoom::slt_Connect m_pNodeClient is null";
        return;
    }
    
    QString strClientID = m_pClientID->text();
    QString strServerIP = m_pServerIP->text();
    QString strServerPort = m_pServerPort->text();
    QString strServerKey = m_pServerKey->text();
    if( strClientID.isEmpty() || strServerIP.isEmpty() || strServerPort.isEmpty() || strServerKey.isEmpty() )
    {
        myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("我的ID、服务端IP或端口或口令输入不完整，请检查！"));
        return;
    }

    // 校验是否为有效IP地址
    if(false == checkIPv4(strServerIP))
    {
        myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("服务端IP非有效IPv4地址，请检查！"));
        return;
    }

    if(false == checkValidNumber(strServerPort))
    {
        myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("服务端端口非有效数字，请检查！"));
        return;
    }

    std::string strID = strClientID.toStdString();
    std::string strIP = strServerIP.toStdString();
    unsigned int uiPort = strServerPort.toInt();
    std::string strKey = strServerKey.toStdString();
    m_pNodeClient->setParams(strID, strID);
    if(false == m_pNodeClient->initAndConnect(strIP, uiPort, strKey))
    {
        myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("连接服务端失败,请确认IP地址、端口和口令是否准确"));
    }
    else
    {
        m_pClientID->setEnabled(false);
        m_pServerIP->setEnabled(false);
        m_pServerPort->setEnabled(false);
        m_pServerKey->setEnabled(false);
        m_pBtnDisConnect->setEnabled(true);
        m_pBtnConnect->setEnabled(false);
        m_strNodeId = strIP + "_" + strID;
    }
}

// 断开服务
void FormChatRoom::slt_Disconnect()
{
    // 断开连接
    m_pNodeClient->disconnect();

    // 恢复按钮和输入框状态
    m_pClientID->setEnabled(true);
    m_pServerIP->setEnabled(true);
    m_pServerPort->setEnabled(true);
    m_pServerKey->setEnabled(true);
    m_pBtnConnect->setEnabled(true);
    m_pBtnDisConnect->setEnabled(false);
    m_strNodeId.clear();
}

// 刷新数据
void FormChatRoom::slt_Update()
{
    
}

// 清空数据
void FormChatRoom::slt_Clear()
{
    m_pMsgInput->clear();
}

// 发送数据
void FormChatRoom::slt_Send()
{
    // 确认网络模块已初始化
    if(nullptr == m_pNodeClient || false == m_pNodeClient->getStatus())
    {
        myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("请先连接到服务端"));
        return;
    }

    MSG_INFO stMsg;
    stMsg.strMsg = m_pMsgInput->document()->toPlainText().toStdString();
    if(stMsg.strMsg.empty())
    {
        return;
    }
    
    // 插入数据后清空输入区
    stMsg.nType = MSG_INFO_TYPE_MSGDATA;
    stMsg.strTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString();
    m_pNodeClient->insertMsg(stMsg);
    m_pMsgInput->clear();

    QString strInfo;        // 消息抬头
    QString strShowMsg;     // 消息内容
    getBrowserShowInfo(stMsg, strInfo, strShowMsg);
    m_pMsgShowInfo->insertHtml(strInfo);
    m_pMsgShowInfo->insertHtml(strShowMsg);
}

// 展示数据
void FormChatRoom::slt_ShowMsgInfo(QString strInfo, QString strMsg)
{
    m_pMsgShowInfo->insertHtml(strInfo);
    m_pMsgShowInfo->insertHtml(strMsg);
}

// 更新节点状态
void FormChatRoom::stl_UpdateNodeStatus(QList<NODE_INFO> listNodeStatus)
{
    if(listNodeStatus.empty())
    {
        return;
    }

    for(auto it : listNodeStatus)
    {
        qDebug() << "FormChatRoom::stl_UpdateNodeStatus " << it.nType << it.strNodeID;
    }
}

// 消息获取线程
void FormChatRoom::threadMsgProc()
{
    if(nullptr == m_pNodeClient)
    {
        return;
    }

    while(!m_bExit)
    {
        std::list<MSG_INFO> listMsgInfo;
        if(nullptr != m_pNodeClient)
        {
            m_pNodeClient->getCallBackMsgWithCondition(listMsgInfo);
        }
        else
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        }
        
        if(m_bExit)
        {
            break;
        }

        QList<NODE_INFO> listNodeStatus;
        listNodeStatus.clear();
        for(auto it : listMsgInfo)
        {
            // 收集节点状态的消息，并通知列表更新
            if( MSG_INFO_TYPE_STATUS_NEW == it.nType || MSG_INFO_TYPE_STATUS_OFF == it.nType || MSG_INFO_TYPE_STATUS_EXIT == it.nType)
            {
                NODE_INFO stNodeStatus;
                stNodeStatus.nType = it.nType;
                stNodeStatus.strNodeID = QString::fromStdString(it.strID);
                listNodeStatus.push_back(stNodeStatus);
            }

            // 跳过非本节点的消息
            if(it.strID == m_strNodeId)
            {
                // 属于本节点的数据，跳过

                continue;
            }

            QString strInfo;        // 消息抬头
            QString strShowMsg;     // 消息内容
            getBrowserShowInfo(it, strInfo, strShowMsg);

            // 不能直接由线程操作控件，需通过信号方式触发
            emit sengMsg2Show(strInfo, strShowMsg);
        }

        // 更新群友列表
        if(!listNodeStatus.empty())
        {
            emit sendListNodeStatus(listNodeStatus);
        }
    }
}
